/*
* Poppy Game Engine - https://pgetemplate.googlecode.com/svn/
* -----------------------------------------------------------------------
* Licensed under the BSD license, see LICENSE in PSPSDK root for details.
*
* Copyright (c) 2008 Poppy
*/

#include "stdafx.h"
#include "CPSPDriver.h"

#ifdef PSP

namespace PGERenderer
{

	static unsigned int __attribute__((aligned(16))) ge_init_list[] =
	{
		0x01000000, 0x02000000, 0x10000000, 0x12000000, 0x13000000, 0x15000000, 0x16000000, 0x17000000,
		0x18000000, 0x19000000, 0x1a000000, 0x1b000000, 0x1c000000, 0x1d000000, 0x1e000000, 0x1f000000,
		0x20000000, 0x21000000, 0x22000000, 0x23000000, 0x24000000, 0x25000000, 0x26000000, 0x27000000,
		0x28000000, 0x2a000000, 0x2b000000, 0x2c000000, 0x2d000000, 0x2e000000, 0x2f000000, 0x30000000,
		0x31000000, 0x32000000, 0x33000000, 0x36000000, 0x37000000, 0x38000000, 0x3a000000, 0x3b000000,
		0x3c000000, 0x3d000000, 0x3e000000, 0x3f000000, 0x40000000, 0x41000000, 0x42000000, 0x43000000,
		0x44000000, 0x45000000, 0x46000000, 0x47000000, 0x48000000, 0x49000000, 0x4a000000, 0x4b000000,
		0x4c000000, 0x4d000000, 0x50000000, 0x51000000, 0x53000000, 0x54000000, 0x55000000, 0x56000000,
		0x57000000, 0x58000000, 0x5b000000, 0x5c000000, 0x5d000000, 0x5e000000, 0x5f000000, 0x60000000,
		0x61000000, 0x62000000, 0x63000000, 0x64000000, 0x65000000, 0x66000000, 0x67000000, 0x68000000,
		0x69000000, 0x6a000000, 0x6b000000, 0x6c000000, 0x6d000000, 0x6e000000, 0x6f000000, 0x70000000,
		0x71000000, 0x72000000, 0x73000000, 0x74000000, 0x75000000, 0x76000000, 0x77000000, 0x78000000,
		0x79000000, 0x7a000000, 0x7b000000, 0x7c000000, 0x7d000000, 0x7e000000, 0x7f000000, 0x80000000,
		0x81000000, 0x82000000, 0x83000000, 0x84000000, 0x85000000, 0x86000000, 0x87000000, 0x88000000,
		0x89000000, 0x8a000000, 0x8b000000, 0x8c000000, 0x8d000000, 0x8e000000, 0x8f000000, 0x90000000,
		0x91000000, 0x92000000, 0x93000000, 0x94000000, 0x95000000, 0x96000000, 0x97000000, 0x98000000,
		0x99000000, 0x9a000000, 0x9b000000, 0x9c000000, 0x9d000000, 0x9e000000, 0x9f000000, 0xa0000000,
		0xa1000000, 0xa2000000, 0xa3000000, 0xa4000000, 0xa5000000, 0xa6000000, 0xa7000000, 0xa8040004,
		0xa9000000, 0xaa000000, 0xab000000, 0xac000000, 0xad000000, 0xae000000, 0xaf000000, 0xb0000000,
		0xb1000000, 0xb2000000, 0xb3000000, 0xb4000000, 0xb5000000, 0xb8000101, 0xb9000000, 0xba000000,
		0xbb000000, 0xbc000000, 0xbd000000, 0xbe000000, 0xbf000000, 0xc0000000, 0xc1000000, 0xc2000000,
		0xc3000000, 0xc4000000, 0xc5000000, 0xc6000000, 0xc7000000, 0xc8000000, 0xc9000000, 0xca000000,
		0xcb000000, 0xcc000000, 0xcd000000, 0xce000000, 0xcf000000, 0xd0000000, 0xd2000000, 0xd3000000,
		0xd4000000, 0xd5000000, 0xd6000000, 0xd7000000, 0xd8000000, 0xd9000000, 0xda000000, 0xdb000000,
		0xdc000000, 0xdd000000, 0xde000000, 0xdf000000, 0xe0000000, 0xe1000000, 0xe2000000, 0xe3000000,
		0xe4000000, 0xe5000000, 0xe6000000, 0xe7000000, 0xe8000000, 0xe9000000, 0xeb000000, 0xec000000,
		0xee000000, 0xf0000000, 0xf1000000, 0xf2000000, 0xf3000000, 0xf4000000, 0xf5000000, 0xf6000000,
		0xf7000000, 0xf8000000, 0xf9000000,
		0x0f000000, 0x0c000000, 0, 0
	};
	
	static unsigned int __attribute__((aligned(16))) context_list[262144];	
	
	void CPSPDriver::InitGraphicSystem()
	{
		assert(!m_pData);
		assert(!m_bIsInited);
		m_pData = new CGraphicSystemData();
		PspGeCallbackData callback;
		callback.signal_func = CallbackSig;
		callback.signal_arg = &m_pData->m_sSettings;
		callback.finish_func = CallbackFin;
		callback.finish_arg = &m_pData->m_sSettings;
		m_pData->m_sSettings.m_iGeCallbackId = sceGeSetCallback(&callback);
		m_pData->m_iGeListExecuted = sceGeListEnQueue((void*)((unsigned int)ge_init_list & 0x1fffffff), 0, m_pData->m_sSettings.m_iGeCallbackId, 0);
		m_pData->m_sSettings.m_iKernelEventFlag = sceKernelCreateEventFlag("PGERendererSignal", 512, 3, 0);
		sceGeListSync(m_pData->m_iGeListExecuted, 0);
		Start();
		m_bIsInited = true;
	}
	
	void CPSPDriver::Start()
	{
		m_pData->m_sList.m_pStart = (unsigned int*)(((unsigned int)context_list) | 0x40000000);
		m_pData->m_sList.m_pCurrent = m_pData->m_sList.m_pStart;
		m_pData->m_iGeListExecuted = sceGeListEnQueue(m_pData->m_sList.m_pStart,m_pData->m_sList.m_pCurrent,m_pData->m_sSettings.m_iGeCallbackId,0);
		m_pData->m_sSettings.m_iSignalOffset = 0;
		
		Setup();
		SetBuffers();
		EndScene();
		
		sceGeDrawSync(0);
		sceDisplayWaitVblankStart();
		sceDisplaySetFrameBuf(m_pData->m_sDrawBuffer.m_pDispBuffer, m_pData->m_sDrawBuffer.m_iFrameWidth, m_pData->m_sDrawBuffer.m_iPixelSize, PSP_DISPLAY_SETBUF_NEXTFRAME);
	}
	
	void CPSPDriver::SetBuffers()
	{
		SendCommandToDatai(m_pData, PSM, m_pData->m_sDrawBuffer.m_iPixelSize);
		SendCommandToDatai(m_pData, FBP, (unsigned int)m_pData->m_sDrawBuffer.m_pFrameBuffer & 0xffffff);
		SendCommandToDatai(m_pData, FBW, (((unsigned int)m_pData->m_sDrawBuffer.m_pFrameBuffer & 0xff000000) >> 8) | m_pData->m_sDrawBuffer.m_iFrameWidth);
		SendCommandToDatai(m_pData, ZBP, (unsigned int)m_pData->m_sDrawBuffer.m_pDepthBuffer & 0xffffff);
		SendCommandToDatai(m_pData, ZBW, (((unsigned int)m_pData->m_sDrawBuffer.m_pDepthBuffer & 0xff000000) >> 8) | m_pData->m_sDrawBuffer.m_iDepthWidth);
		DrawRegion(0, 0, m_pData->m_sDrawBuffer.m_iWidth, m_pData->m_sDrawBuffer.m_iHeight);
		sceDisplaySetMode(0, m_pData->m_sDrawBuffer.m_iWidth, m_pData->m_sDrawBuffer.m_iHeight);
	}
	
	bool CPSPDriver::BeginScene()
	{
		sceDisplaySetFrameBuf((void*)((unsigned int)m_pData->m_pGeEdramAddress + (unsigned int)m_pData->m_sDrawBuffer.m_pDispBuffer), m_pData->m_sDrawBuffer.m_iFrameWidth, m_pData->m_sDrawBuffer.m_iPixelSize, m_pData->m_sSettings.m_iSwapBuffersBehaviour);
		pspDebugScreenSetOffset((int)m_pData->m_sDrawBuffer.m_pFrameBuffer);
		pspDebugScreenSetXY(0,0);
		m_pData->m_iGeListExecuted = sceGeListEnQueue(m_pData->m_sList.m_pStart, m_pData->m_sList.m_pCurrent, m_pData->m_sSettings.m_iGeCallbackId, 0);
		
		return true;
	}
			
	void CPSPDriver::EndScene()
	{
		SendCommandToDatai(m_pData, FINISH,0);
		SendCommandToDatai(m_pData, END,0);
		sceGeListUpdateStallAddr(m_pData->m_iGeListExecuted, m_pData->m_sList.m_pCurrent);
	}
	
	void CPSPDriver::Present()
	{
		register void* temp = m_pData->m_sDrawBuffer.m_pDispBuffer;
		m_pData->m_sDrawBuffer.m_pDispBuffer = m_pData->m_sDrawBuffer.m_pFrameBuffer;
		m_pData->m_sDrawBuffer.m_pFrameBuffer = temp;
		m_pData->m_sList.m_pCurrent = m_pData->m_sList.m_pStart;
		SendCommandToDatai(m_pData, FBP, ((unsigned int)m_pData->m_sDrawBuffer.m_pFrameBuffer) & 0xffffff);
		SendCommandToDatai(m_pData, FBW, ((((unsigned int)m_pData->m_sDrawBuffer.m_pFrameBuffer) & 0xff000000) >> 8) | m_pData->m_sDrawBuffer.m_iFrameWidth);
		if(m_pData->m_bIsClear)
			Clear();
		sceGeDrawSync(0);
	}
	
	void CPSPDriver::Setup()
	{
		static int dither_matrix[16] =
		{
			-4, 0,-3, 1,
			 2,-2, 3,-1,
			-3, 1,-4, 0,
			 3,-1, 2,-2
		};
		SetDither(dither_matrix);
		PatchDivide(16,16);
		ColorMaterial(7);
		Specular(1.0f);
		TexScale(1.0f,1.0f);
		Offset(2048 - (PSP_SCREEN_WIDTH/2), 2048 - (PSP_SCREEN_HEIGHT/2));
		Viewport(2048, 2048, PSP_SCREEN_WIDTH, PSP_SCREEN_HEIGHT);
		DepthRange(0, 65535);
		FrontFace(PGE_CCW);
		ShadeModel(PGE_SMOOTH);
		Scissor(0, 0, m_pData->m_sDrawBuffer.m_iWidth, m_pData->m_sDrawBuffer.m_iHeight);
	}
		
	void CPSPDriver::TermGraphicSystem()
	{
		assert(m_pData);
		assert(m_bIsInited);
		sceKernelDeleteEventFlag(m_pData->m_sSettings.m_iKernelEventFlag);
		sceGeUnsetCallback(m_pData->m_sSettings.m_iGeCallbackId);
		delete m_pData;
		m_pData = NULL;
		m_bIsInited = false;
	}
	
	void CPSPDriver::SendCommandi(int cmd, int argument)
	{
		SendCommandToDatai(m_pData, cmd, argument);
	}
			
	void CPSPDriver::SendCommandf(int cmd, float argument)
	{
		SendCommandToDataf(m_pData, cmd, argument);
	}
	
	void CPSPDriver::Clear()
	{
		struct Vertex
		{
			unsigned int color;
			unsigned short x,y,z;
			unsigned short pad;
		};
		struct Vertex* vertices;
		vertices = (struct Vertex*)GetMemory(2 * sizeof(struct Vertex));

		vertices[0].color = 0;
		vertices[0].x = 0;
		vertices[0].y = 0;
		vertices[0].z = m_pData->m_sContexts.m_uClearDepth;
		vertices[1].color = m_pData->m_sContexts.m_uClearColor;
		vertices[1].x = m_pData->m_sDrawBuffer.m_iWidth;
		vertices[1].y = m_pData->m_sDrawBuffer.m_iHeight;
		vertices[1].z = m_pData->m_sContexts.m_uClearDepth;
		
		SendCommandToDatai(m_pData, CLEAR, (m_pData->m_iClearArea << 8) | 0x01);
		SendCommandToDatai(m_pData, VTYPE, 0x80011C);
		SendCommandToDatai(m_pData, BASE, (((unsigned int)vertices) >> 8) & 0xf0000);
		SendCommandToDatai(m_pData, VADDR, ((unsigned int)vertices) & 0xffffff);
		SendCommandToDatai(m_pData, PRIM, 0x60002);
		SendCommandToDatai(m_pData, CLEAR, 0);
	}
			
	void CPSPDriver::CommandStall()
	{
		sceGeListUpdateStallAddr(m_pData->m_iGeListExecuted, m_pData->m_sList.m_pCurrent);
	}
	
	void CPSPDriver::CallbackFin(int id, void* arg)
	{
		Settings* settings = (Settings*)arg;
		if (settings->m_pFin)
			settings->m_pFin(id & 0xffff);
	}
	
	void CPSPDriver::CallbackSig(int id, void* arg)
	{
		Settings* settings = (Settings*)arg;
	
		settings->m_aSignalHistory[(settings->m_iSignalOffset++) & 15] = id & 0xffff;
	
		if (settings->m_pSig)
			settings->m_pSig(id & 0xffff);
	
		sceKernelSetEventFlag(settings->m_iKernelEventFlag, 1);
	}
	
}

#endif

